﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;

namespace FishServe.Build.Module
{
    class Project
    {
        public string ProjectGuid { get; set; }
        public string AssemblyName { get; set; }
        public bool SignAssembly { get; set; }
        public string TargetFrameworkVersion { get; set; }
        public string DefaultNamespace { get; set; }
        public ProjectRunPostBuildEvent RunPostBuildEvent { get; set; }
        public ProjectOutputType OutputType { get; set; }

        public List<ProjectReference> References { get; set; }
        public List<ProjectContent> Contents { get; set; }
        public List<ProjectProjectReference> ProjectReferences { get; set; }

        internal Project()
        {
            References = new List<ProjectReference>();
            Contents = new List<ProjectContent>();
            ProjectReferences = new List<ProjectProjectReference>();
        }

        internal static Project Load(string projectFullFilename)
        {
            Project project = new Project();

            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(projectFullFilename);

            string projectGuid = "";
            string assemblyName = "";
            bool signAssembly = false;
            string targetFrameworkVersion = "";
            string defaultNamespace = "";
            ProjectRunPostBuildEvent runPostBuildEvent = ProjectRunPostBuildEvent.Undefined;
            ProjectOutputType outputType = ProjectOutputType.Undefined;

            XmlNode xmlNodeLevel1 = xmlDocument.DocumentElement.FirstChild;
            XmlNode xmlNodeLevel2 = null;
            XmlNode xmlNodeLevel3 = null;
            XmlElement xmlElementLevel1 = null;
            XmlElement xmlElementLevel2 = null;
            XmlElement xmlElementLevel3 = null;

            while (xmlNodeLevel1 != null)
            {
                if (xmlNodeLevel1.NodeType == XmlNodeType.Element)
                {
                    xmlElementLevel1 = (XmlElement)xmlNodeLevel1;
                    if (xmlElementLevel1.Name == "PropertyGroup")
                    {
                        xmlNodeLevel2 = xmlElementLevel1.FirstChild;
                        while (xmlNodeLevel2 != null)
                        {
                            if (xmlNodeLevel2.NodeType == XmlNodeType.Element)
                            {
                                xmlElementLevel2 = (XmlElement)xmlNodeLevel2;
                                if (xmlElementLevel2.Name == "ProjectGuid")
                                {
                                    projectGuid = xmlElementLevel2.InnerText;
                                }
                                else if (xmlElementLevel2.Name == "SignAssembly")
                                {
                                    if (xmlElementLevel2.InnerText.ToLower() == "true")
                                        signAssembly = true;
                                }
                                else if (xmlElementLevel2.Name == "AssemblyName")
                                {
                                    assemblyName = xmlElementLevel2.InnerText;
                                }
                                else if (xmlElementLevel2.Name == "TargetFrameworkVersion")
                                {
                                    targetFrameworkVersion = xmlElementLevel2.InnerText;
                                }
                                else if (xmlElementLevel2.Name == "RunPostBuildEvent")
                                {
                                    if (xmlElementLevel2.InnerText.ToLower() == "onbuildsuccess")
                                        runPostBuildEvent = ProjectRunPostBuildEvent.OnBuildSuccess;
                                    else if (xmlElementLevel2.InnerText.ToLower() == "onoutputupdated")
                                        runPostBuildEvent = ProjectRunPostBuildEvent.OnOutputUpdated;
                                }
                                else if (xmlElementLevel2.Name == "OutputType")
                                {
                                    if (xmlElementLevel2.InnerText.ToLower() == "library")
                                        outputType = ProjectOutputType.ClassLibrary;
                                    else if (xmlElementLevel2.InnerText.ToLower() == "winexe")
                                        outputType = ProjectOutputType.WindowsApplication;
                                    else if (xmlElementLevel2.InnerText.ToLower() == "exe")
                                        outputType = ProjectOutputType.ConsoleApplication;
                                }
                                else if (xmlElementLevel2.Name == "RootNamespace")
                                {
                                    defaultNamespace = xmlElementLevel2.InnerText;
                                }
                            }
                            xmlNodeLevel2 = xmlNodeLevel2.NextSibling;
                        }
                    }
                    else if (xmlElementLevel1.Name == "ItemGroup")
                    {
                        // TODO: references

                        xmlNodeLevel2 = xmlElementLevel1.FirstChild;
                        while (xmlNodeLevel2 != null)
                        {
                            if (xmlNodeLevel2.NodeType == XmlNodeType.Element)
                            {
                                xmlElementLevel2 = (XmlElement)xmlNodeLevel2;
                                if (xmlElementLevel2.Name == "Content")
                                {
                                    string includeFilename = xmlElementLevel2.GetAttribute("Include");
                                    ProjectContentCopyType includeFileCopyType = ProjectContentCopyType.Undefined;
                                    xmlNodeLevel3 = xmlElementLevel2.FirstChild;
                                    while (xmlNodeLevel3 != null)
                                    {
                                        if (xmlNodeLevel3.NodeType == XmlNodeType.Element)
                                        {
                                            xmlElementLevel3 = (XmlElement)xmlNodeLevel3;
                                            if (xmlElementLevel3.Name == "CopyToOutputDirectory")
                                            {
                                                if (xmlNodeLevel3.InnerText == "Always")
                                                    includeFileCopyType = ProjectContentCopyType.Always;
                                                else if (xmlNodeLevel3.InnerText == "PreserveNewest")
                                                    includeFileCopyType = ProjectContentCopyType.PreserveNewest;
                                            }
                                        }
                                        xmlNodeLevel3 = xmlNodeLevel3.NextSibling;
                                    }

                                    project.Contents.Add(new ProjectContent(includeFilename, includeFileCopyType));
                                }
                                else if (xmlElementLevel2.Name == "ProjectReference")
                                {
                                    string include = xmlElementLevel2.GetAttribute("Include");
                                    string referencedProjectGuid = "";
                                    string referencedProjectName = "";

                                    xmlNodeLevel3 = xmlElementLevel2.FirstChild;
                                    while (xmlNodeLevel3 != null)
                                    {
                                        if (xmlNodeLevel3.NodeType == XmlNodeType.Element)
                                        {
                                            xmlElementLevel3 = (XmlElement)xmlNodeLevel3;
                                            if (xmlElementLevel3.Name == "Project")
                                                referencedProjectGuid = xmlElementLevel3.InnerText;
                                            else if( xmlElementLevel3.Name == "Name" )
                                                referencedProjectName = xmlElementLevel3.InnerText;
                                        }
                                        xmlNodeLevel3 = xmlNodeLevel3.NextSibling;
                                    }

                                    project.ProjectReferences.Add(new ProjectProjectReference(include, referencedProjectGuid, referencedProjectName));
                                }
                                else if (xmlElementLevel2.Name == "Reference")
                                {
                                    string include = xmlElementLevel2.GetAttribute("Include");
                                    project.References.Add(new ProjectReference(include));
                                }
                            }
                            xmlNodeLevel2 = xmlNodeLevel2.NextSibling;
                        }
                    }
                }
                xmlNodeLevel1 = xmlNodeLevel1.NextSibling;
            }

            project.ProjectGuid = projectGuid;
            project.AssemblyName = assemblyName;
            project.SignAssembly = signAssembly;
            project.TargetFrameworkVersion = targetFrameworkVersion;
            project.DefaultNamespace = defaultNamespace;
            project.RunPostBuildEvent = runPostBuildEvent;
            project.OutputType = outputType;

            return project;
        }
    }

    internal enum ProjectRunPostBuildEvent
    {
        Undefined,
        OnBuildSuccess,
        OnOutputUpdated,
    }

    internal enum ProjectOutputType
    {
        Undefined,
        ClassLibrary,           // "Library"
        WindowsApplication,     // "WinExe"
        ConsoleApplication      // "Exe"
    }
}
